package com.walleipt.ak47.generate;

import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.rowset.SqlRowSet;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.walle.ak47.commons.utils.FileUtils;
import com.walle.ak47.commons.utils.RuntimeUtils;
import com.walle.ak47.commons.utils.StringUtils;
import com.walle.ak47.commons.utils.json.GBuilder;
import com.walleipt.ak47.generate.entity.Attr;
import com.walleipt.ak47.generate.entity.ImportClass;
import com.walleipt.ak47.generate.entity.Method;

import freemarker.template.Configuration;
import freemarker.template.Template;

/**
 * 接口生成器，根据小妖鸡定义的resutful文件结构生成接口源码
 * @author admin
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class Generater 
{
	static final String generateFolder = new File(RuntimeUtils.getProjectResourcePath()).getParentFile().getParentFile()+"/src/main/java/" ;
	static final String targetPackage = "com.walleipt.ak47.services" ;
	static final String templateFolder = Generater.class.getResource("").getFile() ;
	static final String templateFileName = "ServicesTemplate.ftl" ;
	
	
	
	static final String projectName = "commons-services"  ;
	static final String getInterfaceSql = "select url,requestHeaders,requestArgs,responseArgs from interface where projectId=(select id from project where name='%s') and url IS NOT NULL  " ;
	@Autowired
	JdbcTemplate jdbcTemplate ;
	
	@Test
	public void generate() throws Exception
	{
		
		SqlRowSet rs = jdbcTemplate.queryForRowSet( String.format(getInterfaceSql, projectName) ) ;
		while( rs.next() )
		{
			
			String url = rs.getString( "url") ;
			if ( StringUtils.isNotBlank(url))
			{
				String requestHeaders = rs.getString( "requestHeaders" ) ;
				String requestArgs = rs.getString( "requestArgs" ) ;
				String responseArgs = rs.getString( "responseArgs" ) ;
				
				ServicesGenerater servicesGenerater = new ServicesGenerater( url, requestHeaders, requestArgs, responseArgs ) ;
				servicesGenerater.generate();
			}
		}
	}
	
	class ServicesGenerater 
	{
		public String _package ;
		public String _folder ;
		public String _className ;
		
		public String url ;
		public String requestHeaders;
		public String requestArgs;
		public String responseArgs ;
		
		public String _packgeEntity ;
		public String _folderEntity ;
		public String _entityReq; 
		public String _entityResp ;
		
		public ServicesGenerater(){}
		public ServicesGenerater( String url, String requestHeaders, String requestArgs, String responseArgs )
		{
			this.url = url ;
			this.requestHeaders = requestHeaders ;
			this.requestArgs = requestArgs ;
			this.responseArgs = responseArgs ;
			
			this._folder = getAndCreateFolder( url ) ;
			this._package = getAllPackageName( url ) ;
			this._className = getClassName( url ) ;
			
			this._folderEntity = _folder+"/entity" ;
			this._packgeEntity = _package+".entity" ;
			this._entityReq = _className+"Req" ;
			this._entityResp = _className+"Resp" ;
			
		}
		
		public String getAndCreateFolder( String url )
		{
			List<String> packageFields = StringUtils.toListStr( targetPackage, ".") ;
			List<String> urls  = StringUtils.toListStr( url, "/" ) ;
			if ( "api".equals( urls.get(1)) ) urls.remove(1) ;
			
			List<String> list = new ArrayList<String>() ;
			list.addAll(packageFields) ;
			list.addAll( urls ) ;
			
			String folder = generateFolder ;
 			for ( String field: list) {
				if ( StringUtils.isNotBlank(field) )
					folder += (field+"/" ) ;
			}
			folder = folder.substring(0, folder.length()-1 ) ;
			FileUtils.mkdirs(folder);
			
			return folder ;
		}
		
		public String getAllPackageName( String url  )
		{
			List<String> packageFields = StringUtils.toListStr( targetPackage, ".") ;
			List<String> urls  = StringUtils.toListStr( url, "/" ) ;
			if ( "api".equals( urls.get(1)) ) urls.remove(1) ;
			
			List<String> list = new ArrayList<String>() ;
			list.addAll(packageFields) ;
			list.addAll( urls ) ;
			
			String folder = "" ;
			if ( "api".equals( list.get(0)) ) list.remove(0) ;
			for ( String field: list) {
				if ( StringUtils.isNotBlank(field) )
					folder += (field+"." ) ;
			}
			folder = folder.substring(0, folder.length()-1 ) ;
			
			return folder ;
		}
		
		public String getClassName( String url )
		{
			String[] urls  = StringUtils.split( url, "/" ) ;
			_className = urls[urls.length-1] ;
			return StringUtils.toUpperCaseFirstOne(_className )+"Api" ; 
		}
		
		public void generate() throws Exception
		{
			generateApiCode() ;
	  		generateEntityCode( _folderEntity, _packgeEntity, _entityReq, requestArgs );
	  		generateEntityCode( _folderEntity, _packgeEntity, _entityResp, responseArgs);
		}
		
		public void generateApiCode() throws Exception
		{
			String importCode = new String( "import "+_package+".entity."+_className+"Req ; " ) ;
			String getReqCode = new String( _entityReq+" req = GBuilder.gson().fromJson(IOUtils.toString( request.getInputStream() , \"UTF-8\"), "+_entityReq+".class ) ;" ) ;
			
			Configuration cfg = new Configuration(); 
			cfg.setDirectoryForTemplateLoading( new File( templateFolder ) ) ;
			Template t = cfg.getTemplate( templateFileName ); 
			//创建插值的Map 
			Map<String,Object> map = new HashMap<String,Object>(); 
			map.put("className", _className ); 
	  		map.put("package", _package ); 
	  		map.put("importCode", importCode ); 
	  		map.put("requiredCode", getReqCode ); 
	  		//执行插值，并输出到指定的输出流中 
	  		File file = new File(_folder+"/"+_className+".java") ;
	  		if ( !FileUtils.exists( file.getAbsolutePath() ) )
	  		{
	  			file.createNewFile() ;
		  		t.process(map, new FileWriter( file ) );
	  		}
		}
		public void generateEntityCode( String __folder, String __package, String className, String args ) throws Exception
		{
		
			Set<ImportClass> importClasses = new HashSet<ImportClass>() ;
			List<Attr> attrs = new ArrayList<Attr>() ;
			List<Method> getAttrsMethods = new ArrayList<Method>() ;
			
			JsonArray jsonArray = GBuilder.getJsonArray( args ) ;
			Iterator<JsonElement> iter = jsonArray.iterator() ;
			while( iter.hasNext() )
			{
				JsonElement elem = iter.next() ;
				JsonObject obj = elem.getAsJsonObject() ;
				String name = obj.get("name").getAsString() ;
				 
				if ( "string".equals(obj.get("type").getAsString()) )
				{
					attrs.add( new Attr( "String", name) ) ;
					getAttrsMethods.add( new Method( "String", StringUtils.toUpperCaseFirstOne(name), name ) ) ;
				}
				else if ( "boolean".equals(obj.get("type").getAsString()) )
				{
					attrs.add( new Attr( "Boolean", name) ) ;
					getAttrsMethods.add( new Method( "Boolean", StringUtils.toUpperCaseFirstOne(name), name ) ) ;
				}
				else if ( "integer".equals(obj.get("type").getAsString()) )
				{
					attrs.add( new Attr( "Integer", name) ) ;
					getAttrsMethods.add( new Method( "Integer", StringUtils.toUpperCaseFirstOne(name), name ) ) ;
				}
				else if ( "double".equals(obj.get("type").getAsString()) )
				{
					attrs.add( new Attr( "Double", name) ) ;
					getAttrsMethods.add( new Method( "Double", StringUtils.toUpperCaseFirstOne(name), name ) ) ;
				}
				else if ( "number".equals(obj.get("type").getAsString()) )
				{
					attrs.add( new Attr( "Number", name) ) ;
					getAttrsMethods.add( new Method( "Number", StringUtils.toUpperCaseFirstOne(name), name ) ) ;
				}
				else if ( "object".equals(obj.get("type").getAsString()) )
				{
					String children = obj.get("children").getAsJsonArray().toString() ;
					String entityPackage = this._package+".entity" ; 
					importClasses.add( new ImportClass(entityPackage+"."+StringUtils.toUpperCaseFirstOne(name)) ) ;
					attrs.add( new Attr( StringUtils.toUpperCaseFirstOne(name), name) ) ;
					getAttrsMethods.add( new Method( StringUtils.toUpperCaseFirstOne(name), StringUtils.toUpperCaseFirstOne(name), name ) ) ;
					generateEntityCode( __folder, __package, StringUtils.toUpperCaseFirstOne(name), children ) ;
				}
				else if ( "array[string]".equals(obj.get("type").getAsString()) )
				{
					importClasses.add( new ImportClass( "java.util.List" ) ) ;
					attrs.add( new Attr( "List<String>", name) ) ;
					String children = obj.get("children").getAsJsonArray().toString() ;
					generateEntityCode( __folder, __package, StringUtils.toUpperCaseFirstOne(name), children ) ;
				}
				else if ( "array[boolean]".equals(obj.get("type").getAsString()) )
				{
					importClasses.add( new ImportClass( "java.util.List" ) ) ;
					attrs.add( new Attr( "List<Boolean>", name) ) ;
					String children = obj.get("children").getAsJsonArray().toString() ;
					generateEntityCode( __folder, __package, StringUtils.toUpperCaseFirstOne(name), children ) ;
				}
				else if ( "array[integer]".equals(obj.get("type").getAsString()) )
				{
					importClasses.add( new ImportClass( "java.util.List" ) ) ;
					attrs.add( new Attr( "List<Integer>", name) ) ;
					String children = obj.get("children").getAsJsonArray().toString() ;
					generateEntityCode( __folder, __package, StringUtils.toUpperCaseFirstOne(name), children ) ;
				}
				else if ( "array[double]".equals(obj.get("type").getAsString()) )
				{
					importClasses.add( new ImportClass( "java.util.List" ) ) ;
					attrs.add( new Attr( "List<Double>", name) ) ;
					String children = obj.get("children").getAsJsonArray().toString() ;
					generateEntityCode( __folder, __package, StringUtils.toUpperCaseFirstOne(name), children ) ;
				}
				else if ( "array[number]".equals(obj.get("type").getAsString()) )
				{
					importClasses.add( new ImportClass( "java.util.List" ) ) ;
					attrs.add( new Attr( "List<Number>", name) ) ;
					String children = obj.get("children").getAsJsonArray().toString() ;
					generateEntityCode( __folder, __package, StringUtils.toUpperCaseFirstOne(name), children ) ;
				}
				else if ( "array[object]".equals(obj.get("type").getAsString()) )
				{
					importClasses.add( new ImportClass( "java.util.List" ) ) ;
					attrs.add( new Attr( "List<"+StringUtils.toUpperCaseFirstOne(name)+">", name) ) ;
					String children = obj.get("children").getAsJsonArray().toString() ;
					generateEntityCode( __folder, __package, StringUtils.toUpperCaseFirstOne(name), children ) ;
				}
			}
			
			Configuration cfg = new Configuration(); 
			cfg.setDirectoryForTemplateLoading( new File( templateFolder ) ) ;
			Template t = cfg.getTemplate( "Entity.ftl" ); 
			//创建插值的Map 
			Map<String,Object> map = new HashMap<String,Object>(); 
	  		map.put("package", __package ); 
			map.put("className", className ); 
	  		map.put("importClasses", importClasses );
	  		map.put("attrs", attrs ); 
	  		map.put("getAttrsMethods", getAttrsMethods ); 
	  		//执行插值，并输出到指定的输出流中 
	  		FileUtils.mkdirs(__folder);
	  		File file = new File( __folder+"/"+className+".java") ;
	  		if ( !FileUtils.exists( file.getAbsolutePath() ) )
	  		{
	  			file.createNewFile() ;
		  		t.process(map, new FileWriter( file ) );
	  		}
		}
		
		 
	}

}
